Skip to content

feat: V3 K8S 매니페스트 + ECR Credential Provider + 설계 확정 - #278

Merged
WAFriend3416 merged 3 commits into
mainfrom
feat/v3-k8s-iac
Mar 10, 2026
Merged

feat: V3 K8S 매니페스트 + ECR Credential Provider + 설계 확정#278
WAFriend3416 merged 3 commits into
mainfrom
feat/v3-k8s-iac

Conversation

@WAFriend3416

Copy link
Copy Markdown
Contributor

Summary

V3 K8S 클러스터 수동 배포 E2E 검증 결과를 반영하고, ECR 인증 자동화 및 Stateful 배치 전략을 확정합니다.

1. V3 K8S Plain YAML 매니페스트 (12파일)

  • k8s/apps/ 하위에 namespace, backend, frontend, ai-server, networking 매니페스트 작성
  • Gateway Fabric: DaemonSet 전환 + nginx.service.type/nodePorts 키 수정 (수동 배포에서 발견)
  • ALB health check: /healthz/ (Gateway가 /healthz 미지원)
  • HTTPRoute: /api → backend:8080, / → frontend:3000

2. ECR Credential Provider Ansible Role

  • imagePullSecrets(12시간 만료, 수동 갱신) → kubelet ECR Credential Provider(IAM 자동 인증)로 전환
  • 새 role: ecr-credential-provider (바이너리 설치 + config + kubelet EXTRA_ARGS)
  • site.yml Phase 1에 추가 (kubeadm init/join 전 실행)

3. Stateful 배치 전략 확정

  • Phase 2 K8S StatefulSet 이관 계획 폐기
  • DB/MQ 워크로드를 K8S 외부 EC2에서 영구 운영으로 결정
  • data NS 제거 (6개 → 5개 NS), NetworkPolicy/RBAC 정리

배경

2026-03-10 V3 K8S 클러스터에 매니페스트 수동 배포 → E2E 검증 완료:

  • 6/6 Pod Running, ALB TG 3/3 healthy
  • https://dev.dojangkok.cloud/ 200 OK, /api/actuator/health 401 (인증 정상)
  • Route 53 전환 테스트 → 원복 완료, 클러스터 destroy 완료

발견 이슈 8건 (ImagePullBackOff, FE probe 404, ALB 502, Gateway reconcile 등) 해결 후 코드에 반영.

Test plan

  • Ansible dry-run: ansible-playbook site.yml --check (ECR role 포함)
  • Terraform plan: ALB health_check_path 변경 확인
  • 다음 terraform apply + ansible-playbook 시 ECR Credential Provider 자동 설치 검증
  • 매니페스트 kubectl apply 후 imagePullSecrets 없이 이미지 pull 성공 확인

- 12개 매니페스트 작성 (namespace, backend, frontend, ai-server, networking)
- Gateway Fabric: DaemonSet 전환 + nginx.service.type/nodePorts 키 수정
- ALB health check: /healthz → / (Gateway가 /healthz 미지원)
- HTTPRoute: /api → backend:8080, / → frontend:3000
- E2E 검증 완료 (6/6 Running, ALB TG 3/3 healthy)
kubelet이 IAM role로 ECR 인증 토큰을 자동 갱신하도록 설정.
imagePullSecrets(12시간 만료) 방식을 대체하여 운영 부담 제거.

- 새 role: ecr-credential-provider (바이너리 설치 + 설정 + kubelet 연동)
- site.yml Phase 1에 role 추가 (kubeadm init/join 전 실행)
- group_vars: ecr_credential_provider_version 1.31.1
Phase 2 K8S StatefulSet 이관 계획을 폐기하고,
DB/MQ 워크로드를 K8S 외부 EC2에서 영구 운영하기로 결정.

- data NS 제거 (6개 → 5개 NS)
- ExternalName Service로 투명한 DB 접근
- NetworkPolicy/RBAC에서 data NS 관련 규칙 정리
- AZ 종속 EBS 설명 간소화 (인프라 Pod 전용 스토리지로 한정)
@github-actions

Copy link
Copy Markdown
Contributor

Terraform Plan Result

Step Status
Format
Init
Validate
Plan ✅ (no changes)
Plan Output
data.aws_internet_gateway.existing: Reading...
module.security_groups.aws_security_group.this["k8s-cp"]: Refreshing state... [id=sg-0ff5fd5d2a07640f0]
data.aws_subnet.existing_public_2c: Reading...
data.aws_subnet.existing_public_2a: Reading...
module.k8s_networking.aws_route_table.private["b"]: Refreshing state... [id=rtb-0d0c99a17bf303955]
module.k8s_networking.aws_route_table.private["a"]: Refreshing state... [id=rtb-023793c4ac7db4f54]
module.k8s_nodes.data.aws_ami.ubuntu: Reading...
module.k8s_networking.aws_route_table.private["c"]: Refreshing state... [id=rtb-07db0f1b2c42671eb]
module.security_groups.aws_security_group.this["alb"]: Refreshing state... [id=sg-0b8e1d2e44166a5a6]
module.alb.aws_lb_target_group.gateway: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-2:662505429975:targetgroup/k8s-dev-k8s-gw/00385e7d20ca599a]
data.aws_internet_gateway.existing: Read complete after 0s [id=igw-09f0f9ca0e2253420]
module.security_groups.aws_security_group.this["k8s-worker"]: Refreshing state... [id=sg-056c4fe462113ace0]
module.nat_instance.aws_iam_role.nat: Refreshing state... [id=k8s-dev-nat-role]
data.aws_subnet.existing_public_2c: Read complete after 0s [id=subnet-08e037b9fbd856118]
data.aws_subnet.existing_public_2a: Read complete after 0s [id=subnet-0d0295b4a08a503a9]
data.aws_vpc.existing: Reading...
module.nat_instance.aws_security_group.nat: Refreshing state... [id=sg-09193e8d7fb4e7f2a]
module.k8s_networking.aws_subnet.subnets["k8s-2a"]: Refreshing state... [id=subnet-006a7b0455b5c0ca8]
module.k8s_nodes.data.aws_ami.ubuntu: Read complete after 1s [id=ami-05d7ff9706f910b7d]
module.k8s_networking.aws_subnet.subnets["k8s-2c"]: Refreshing state... [id=subnet-044524b3532625c56]
module.k8s_networking.aws_subnet.subnets["public-2b"]: Refreshing state... [id=subnet-0057834ab7ce554cb]
module.k8s_networking.aws_subnet.subnets["k8s-2b"]: Refreshing state... [id=subnet-0749573b963c74555]
module.iam.aws_iam_role.k8s_node: Refreshing state... [id=k8s-dev-k8s-node-role]
module.nat_instance.data.aws_ami.ubuntu: Reading...
module.security_groups.aws_security_group_rule.ingress["alb-0"]: Refreshing state... [id=sgrule-3218330773]
module.security_groups.aws_security_group_rule.ingress["k8s-cp-0"]: Refreshing state... [id=sgrule-1676911879]
module.security_groups.aws_security_group_rule.ingress["alb-1"]: Refreshing state... [id=sgrule-732673459]
module.security_groups.aws_security_group_rule.ingress["k8s-cp-5"]: Refreshing state... [id=sgrule-1499700432]
module.security_groups.aws_security_group_rule.ingress["k8s-cp-1"]: Refreshing state... [id=sgrule-3493547302]
module.security_groups.aws_security_group_rule.ingress["k8s-cp-6"]: Refreshing state... [id=sgrule-3522566221]
module.security_groups.aws_security_group_rule.ingress["k8s-cp-4"]: Refreshing state... [id=sgrule-3063997279]
module.security_groups.aws_security_group_rule.ingress["k8s-worker-0"]: Refreshing state... [id=sgrule-3753686589]
module.nat_instance.data.aws_ami.ubuntu: Read complete after 0s [id=ami-05d7ff9706f910b7d]
module.security_groups.aws_security_group_rule.ingress["k8s-cp-2"]: Refreshing state... [id=sgrule-375019914]
module.security_groups.aws_security_group_rule.ingress["k8s-worker-2"]: Refreshing state... [id=sgrule-3414184649]
module.security_groups.aws_security_group_rule.ingress["k8s-cp-3"]: Refreshing state... [id=sgrule-1980510265]
module.security_groups.aws_security_group_rule.ingress["k8s-worker-1"]: Refreshing state... [id=sgrule-1125504596]
module.security_groups.aws_security_group_rule.ingress["k8s-worker-3"]: Refreshing state... [id=sgrule-1491813329]
module.security_groups.aws_security_group_rule.egress["alb"]: Refreshing state... [id=sgrule-1740486928]
module.security_groups.aws_security_group_rule.egress["k8s-worker"]: Refreshing state... [id=sgrule-2652448312]
module.security_groups.aws_security_group_rule.egress["k8s-cp"]: Refreshing state... [id=sgrule-1087755363]
module.k8s_networking.aws_route_table.public[0]: Refreshing state... [id=rtb-0234648ab1d6c6ac7]
data.aws_vpc.existing: Read complete after 1s [id=vpc-08b809f7d33f0f9b1]
aws_security_group_rule.alb_to_worker_nodeport: Refreshing state... [id=sgrule-4173098477]
module.k8s_networking.aws_route_table_association.private["k8s-2a"]: Refreshing state... [id=rtbassoc-0a3dce9a0a389b0cf]
module.k8s_networking.aws_route_table_association.private["k8s-2b"]: Refreshing state... [id=rtbassoc-07b1bbf706ef41718]
module.k8s_networking.aws_route_table_association.private["k8s-2c"]: Refreshing state... [id=rtbassoc-08cd3d3e5433911d6]
module.nat_instance.aws_iam_instance_profile.nat: Refreshing state... [id=k8s-dev-nat-profile]
module.nat_instance.aws_iam_role_policy_attachment.nat_ssm: Refreshing state... [id=k8s-dev-nat-role-20260310035839209300000005]
module.nat_instance.aws_iam_role_policy.nat_self_heal: Refreshing state... [id=k8s-dev-nat-role:nat-self-heal]
module.iam.aws_iam_role_policy.ssm_s3: Refreshing state... [id=k8s-dev-k8s-node-role:ssm-s3-transfer]
module.iam.aws_iam_role_policy_attachment.ssm: Refreshing state... [id=k8s-dev-k8s-node-role-20260310035839854000000006]
module.iam.aws_iam_instance_profile.k8s_node: Refreshing state... [id=k8s-dev-k8s-node-profile]
module.iam.aws_iam_role_policy.ebs_csi: Refreshing state... [id=k8s-dev-k8s-node-role:ebs-csi]
module.iam.aws_iam_role_policy.ecr_pull: Refreshing state... [id=k8s-dev-k8s-node-role:ecr-pull]
module.k8s_networking.aws_route_table_association.public["public-2b"]: Refreshing state... [id=rtbassoc-0ca6e9ade30aa219a]
module.alb.aws_lb.this: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-2:662505429975:loadbalancer/app/k8s-dev-k8s-alb/af9df043ce1c7b32]
module.nat_instance.aws_launch_template.nat: Refreshing state... [id=lt-0f3ff06987e414068]
module.k8s_nodes.aws_instance.workers["w-2a-1"]: Refreshing state... [id=i-0d1c25223ccae44b7]
module.k8s_nodes.aws_instance.control_plane: Refreshing state... [id=i-073813e7ee896570b]
module.k8s_nodes.aws_instance.workers["w-2b-1"]: Refreshing state... [id=i-01120d8b966430c0a]
module.k8s_nodes.aws_instance.workers["w-2c-1"]: Refreshing state... [id=i-036d342fc5239344a]
module.nat_instance.aws_autoscaling_group.nat: Refreshing state... [id=k8s-dev-nat-asg]
module.alb.aws_lb_listener.https[0]: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-2:662505429975:listener/app/k8s-dev-k8s-alb/af9df043ce1c7b32/1a50b42bc9749a61]
module.alb.aws_lb_listener.http: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-2:662505429975:listener/app/k8s-dev-k8s-alb/af9df043ce1c7b32/fb6b7b1da0dfa7ba]
module.alb.aws_lb_target_group_attachment.workers["w-2b-1"]: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-2:662505429975:targetgroup/k8s-dev-k8s-gw/00385e7d20ca599a-2026031003590453750000000e]
module.alb.aws_lb_target_group_attachment.workers["w-2a-1"]: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-2:662505429975:targetgroup/k8s-dev-k8s-gw/00385e7d20ca599a-2026031003590465190000000f]
module.alb.aws_lb_target_group_attachment.workers["w-2c-1"]: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-2:662505429975:targetgroup/k8s-dev-k8s-gw/00385e7d20ca599a-2026031003590419270000000d]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.
Releasing state lock. This may take a few moments...

Pushed by: @WAFriend3416

@github-actions

Copy link
Copy Markdown
Contributor

Ansible Syntax Check Result ✅

Step Status
Syntax Check
Lint

Pushed by: @WAFriend3416

@WAFriend3416
WAFriend3416 merged commit c763902 into main Mar 10, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant